package org.budo.redis.jdbc.driver.executor.socket;

import org.budo.jdbc.driver.statement.JdbcStatement;
import org.budo.redis.jdbc.driver.executor.AbstractRedisStatementExecutor;
import org.budo.redis.jdbc.driver.statement.AUTH;
import org.budo.support.lang.util.ByteArray;
import org.budo.support.lang.util.StringUtil;

/**
 * @author lmw
 */
public abstract class AbstractSocketRedisStatementExecutor extends AbstractRedisStatementExecutor {
    protected static final String SPACE = " ", //
            QUOT = "\"", //
            NOFIELD = "nofield", //
            CRLF = "\r\n";

    protected static final byte[] SPACE_BYTES = SPACE.getBytes(), //
            QUOT_BYTES = QUOT.getBytes(), //
            NOFIELD_BYTES = NOFIELD.getBytes(), //
            CRLF_BYTES = CRLF.getBytes();

    private BudoSocketRedisStatementTransporter transporter;

    public BudoSocketRedisStatementTransporter getTransporter() {
        if (null != this.transporter) {
            return this.transporter;
        }

        synchronized (AbstractSocketRedisStatementExecutor.class) {
            if (null != this.transporter) {
                return this.transporter;
            }

            this.transporter = new BudoSocketRedisStatementTransporterImpl(this.getJdbcUrl().getHost(), this.getJdbcUrl().getPort());

            if (!StringUtil.isEmpty(this.getPassword())) {
                this.request(AUTH.class, this.getPassword().getBytes());
            }
        }

        return this.transporter;
    }

    protected Object request(Class<? extends JdbcStatement> statement, byte[]... params) {
        ByteArray byteArray = new ByteArray() //
                .write(statement.getSimpleName().getBytes()) //
                .write(SPACE_BYTES) //
                .writeJoin(params, SPACE_BYTES)//
                .write(CRLF_BYTES);

        byte[] command = byteArray.getBytes();
        Object response = this.request(command);
        return response;
    }

    protected Object request(byte[] command) {
        this.getTransporter().writeAndFlush(command);
        return this.getTransporter().readResponse();
    }

    @Override
    public void close() {
        this.getTransporter().close();
    }

    @Override
    public String toString() {
        return super.toString() + ", transporter=" + this.transporter;
    }
}